package com.dingwen.treasure.core.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 　DebugLogAspect： debug 日志： 实现可配置开启关闭等，记录方法入参、返回值、耗时等
 * 　@author dingwen
 * 　@date 2022/6/3
 *
 */
@Component
@Aspect
@Slf4j
@RequiredArgsConstructor
@ConditionalOnProperty(name = "treasure.log.debug",havingValue = "true")
public class DebugLogAspect {

    /**
     * 线程隔离： 开始时间
     */
    ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * 定义切入点: 以 Controller 结尾类的所有方法
     */
    @Pointcut(value = "execution(* com.dingwen.treasure..*Controller.*(..))")
    public void pointcut(){

    }

    /**
     * 使用环绕通知
     */
    @Around("pointcut()")
    public Object debugLog(ProceedingJoinPoint pjp) throws Throwable {
        startTime.set(System.currentTimeMillis());
        //使用ServletRequestAttributes请求上下文获取方法更多
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        String className = pjp.getSignature().getDeclaringTypeName();
        String methodName = pjp.getSignature().getName();
        //使用数组来获取参数
        Object[] array = pjp.getArgs();
        ObjectMapper mapper = new ObjectMapper();
        //执行函数前打印日志
        log.info("调用前：{}：{},传递的参数为：{}", className, methodName, mapper.writeValueAsString(array));
        log.info("URL:{}", request.getRequestURL().toString());
        log.info("IP地址：{}", request.getRemoteAddr());
        //调用整个目标函数执行
        Object obj = pjp.proceed();
        //执行函数后打印日志
        log.info("调用后：{}：{},返回值为：{}", className, methodName, mapper.writeValueAsString(obj));
        log.info("耗时：{}ms", System.currentTimeMillis() - startTime.get());
        startTime.remove();
        return obj;
    }

}
